#include <stdlib.h>

#include "lib.h"

#include "slotguts.h"
#include "dianeguts.h"
#include "getrand.h"

enum WheelContents 
{
    BLANK, 
    BAR1, 
	BAR2,
	BAR3,
	HAZARD_1,
	HAZARD_2,
	HAZARD_3,
	HAZARD_4,
	CLOSEDDOOR,
};


enum SpinResult
{
	EVT_LOSER = 0,
	EVT_ANY5BARS,
	EVT_5_BAR1,
	EVT_5_BAR2,
	EVT_5_BAR3,
	EVT_ANY5HAZARDS,
	EVT_5_HAZARD_1,
	EVT_5_HAZARD_2,
	EVT_5_HAZARD_3,
	EVT_5_HAZARD_4,
	NUMEVENTS,
};

#define CLOSED_DOOR_STOP		10
#define SAVED_MULTI				0


DianeSlotGuts::DianeSlotGuts()
{
	for(int32 i=0;i<7;i++)
		cDoorOpen[i] = false; 
}
        
DianeSlotGuts::~DianeSlotGuts()
{
}


bool8 
DianeSlotGuts::isValidGuts()
{
    return (getGutsId() >= 1300 && getGutsId() < 1400);
}

uint8
DianeSlotGuts::classifyStops(uint8* stops,uint8 bet, uint8 line)
{
	uint64 resultMASK = ((uint64)1 << EVT_LOSER);

	int32 i, blank = 0, 
			 bar1 = 0, bar2 = 0, bar3 = 0,   
			 hazard_1 = 0, hazard_2 = 0,
			 hazard_3 = 0, hazard_4 = 0,
			 closeddoors = 0;

	for (i = 0; i < getReelCount(); i++)
	{
		switch ( getIcon(i, stops[i])->iconid )
		{
			case BLANK:
				blank++;
				break;
				
			case BAR1:
				bar1++;
				break;
				
			case BAR2:
				bar2++;
				break;
				
			case BAR3:
				bar3++;
				break;
				
			case HAZARD_1:
				hazard_1++;
				break;
				
			case HAZARD_2:
				hazard_2++;
				break;
				
			case HAZARD_3:
				hazard_3++;
				break;
				
			case HAZARD_4:
				hazard_4++;
				break;
				
			case CLOSEDDOOR:
				closeddoors++;
				break;

			default:
				ASSERT(!"Bad Icon Type");
				break;

		}
	}

	int32 bars = bar1 + bar2 + bar3;
	int32 hazards = hazard_1 + hazard_2 + hazard_3 + hazard_4;

	if (bars >= 5)
		resultMASK |= ((uint64)1 << EVT_ANY5BARS);

	if (bar1 >= 5)
		resultMASK |= ((uint64)1 << EVT_5_BAR1);

	if (bar2 >= 5)
		resultMASK |= ((uint64)1 << EVT_5_BAR2);

	if (bar3 >= 5)
		resultMASK |= ((uint64)1 << EVT_5_BAR3);
	
	if (hazards >= 5)
		resultMASK |= ((uint64)1 << EVT_ANY5HAZARDS);

	if (hazard_1 >= 5)
		resultMASK |= ((uint64)1 << EVT_5_HAZARD_1);

	if (hazard_2 >= 5)
		resultMASK |= ((uint64)1 << EVT_5_HAZARD_2);

	if (hazard_3 >= 5)
		resultMASK |= ((uint64)1 << EVT_5_HAZARD_3);

	if (hazard_4 >= 5)
		resultMASK |= ((uint64)1 << EVT_5_HAZARD_4);

	uint8 multiplierIDX = 0;
	if (closeddoors == 0)
		multiplierIDX = getrand()%4;

	m_subGame->update(SAVED_MULTI, multiplierIDX+1); 

	//offset the result by the paytable number to find the correct payout
	uint8  ptjump = NUMEVENTS * multiplierIDX;

	uint8  result = EVT_LOSER;
	int32 payOut = 0;

	//we got progressive
	if (multiplierIDX == 3 && (resultMASK & ((uint64)1 << EVT_5_HAZARD_4)) != 0)
	{
		result = EVT_5_HAZARD_4;
	}
	else
	{
		//loop thru all events that we won and choose the one with the highest payout
		for(i=0;i<NUMEVENTS;i++)
		{
			//check all payouts
			if ((resultMASK & ((uint64)1 << i)) != 0 &&
				getPayout(bet, ptjump + i)->payoutAmount > payOut)
			{
				result = i;
				payOut = getPayout(bet, ptjump + i)->payoutAmount;
			}
		}
	}

#ifdef DEBUGVERBOSE
	DEBUGMSG(("DianeGuts.cpp - Payout: %s",
              getPayout(bet, ptjump + result)->payoutName));
#endif

	return ptjump + result;
}

void
DianeSlotGuts::spin(SlotSpin *spin)
{
    uint8 *stops = new uint8[getReelCount()];
    uint8 i;

	//count open doors
	int32 opendoors = 0;
	for(i=0;i<7;i++)
	{
		if (cDoorOpen[i] == true)
		{
			opendoors++;
		}
	}

	//they can't pick over 5 doors
	if (opendoors > 5)
	{
		m_hardMalfunction = true;	
		return;
	}

	//they should have picked 5 doors to open.. if they did not then we will open five for them
	for(i=0;i<7 && opendoors < 5;i++)
	{
		if (cDoorOpen[i] == false)
		{
			cDoorOpen[i] = true;
			opendoors++;
		}
	}

	for ( i = 0; i < getReelCount(); i++)
    {
		stops[i] = findPositionByWeight(getrand(), i);
    }

	//2 coin gives you one chance to open a door
	if (spin->getBet() >= 2)
	{
		uint8 door = getrand()%7;

		if (cDoorOpen[door] == false)
		{
			//open if for them
			cDoorOpen[door] = true;
		}

	}

	//3 coin gives you another chance to open a door
	if (spin->getBet() >= 3)
	{
		uint8 door = getrand()%7;

		if (cDoorOpen[door] == false)
		{
			//open if for them
			cDoorOpen[door] = true;
		}
	}

	//set closed doors to closed door stop
	for(i=0;i<7;i++)
	{
		if (cDoorOpen[i] == false)
		{
			stops[i] = CLOSED_DOOR_STOP;
		}
	}

    spin->setStops(getReelCount(), stops);

	classifyResult(spin);

    spin->setSpinComplete(true);

    m_spins.push_back(spin);

#ifdef DEBUGVERBOSE

	DEBUGMSG(("DianeGuts.cpp - Spin: bet(%d) payout(%d) jackpot(%d)",
              spin->getTotalBet(), spin->getTotalPayoutAmount() / m_info->creditValue, spin->getJackpot()));

    for ( uint8 reelid = 0; reelid < getReelCount(); reelid++ )
    {
        DEBUGMSG(("                     wheel %d: [%s])",
                  reelid, 
                  getIcon(reelid, spin->getStops()[reelid])->iconName));
    }
#endif

    delete [] stops;
	setGameComplete(true);

	//close all the doors and let them choose which to open
	for(i=0;i<7;i++)
		cDoorOpen[i] = false;
}


void
DianeSlotGuts::playBonusGame(uint8 bonusGameType, int32 bonusDataCount, int32 *bonusData)
{
	DEBUGMSG(("bonusGameType: %d", bonusGameType));
	DEBUGMSG(("bonusDataCount: %d", bonusDataCount));

	int32 current = 0;

	for(int32 i=0;i<7;i++)
		cDoorOpen[i] = false;

	if (bonusGameType == 0)	//open doors requested
	{
		if (bonusDataCount == 7)
		{
			for(int32 i=0;i<7;i++)
			{
				if (bonusData[i])	//the door is closed
				{
					cDoorOpen[i] = true;

					if (++current == 5)		//allow only 5 doors to be open
						break;
				}
			}
		}
		else
		{
			//bad msg
			ASSERT(0);
		}
	}
	else
	{
		//unkown bonus game
		ASSERT(0);
	}
}
